<?php

namespace Trawind\Basics\Transformers;

use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Trawind\Basics\TrawindTransformer;
use Trawind\Helpers\HttpClientHelper;
use Trawind\Helpers\StrHelper;
use Trawind\Remotes\Repositories\Account\Account\ChannelRepositoryEloquent;
use Trawind\Remotes\Repositories\Account\Account\CompanyRepositoryEloquent;
use Trawind\Remotes\Repositories\Account\Account\DepartmentRepositoryEloquent;
use Trawind\Remotes\Repositories\User\UserRepositoryEloquent;
use TrawindCloud\Contracts\Repositories\Product\Item\UnitRepository;

/**
 * Created by @trawindcloud-product-service
 * Author: Evan
 * Time: 2022/3/1 11:17
 */
class RemoteFieldTransform
{


    protected function parseTransformRequestParam()
    {
        $data = [];
        $params = explode(';', request()->input('transform', ''));
        foreach ($params as $param) {
            $mapFields = explode(':', $param);
            $mapField = $mapFields[0];
            $showField = $mapFields[1] ?? 'name';
            $data[$mapField] = explode(',', $showField);
        }
        return $data;
    }


    private function isIncludeTransformField($field)
    {
        $includeArr = explode(',', request()->input('include'));

        if (Str::contains($field, '.')) {
            $prefix = Str::before($field, '.');
            return !in_array($prefix, $includeArr, true);
        }
        return false;
    }


    public function __invoke(array $data, TrawindTransformer $transformer)
    {
        $remoteMap = $transformer::transformMap();
        $result = $promises = [];
        $httpClient = HttpClientHelper::factory()->client();

        $transformParam = $this->parseTransformRequestParam();
        $transformParamFields = array_keys($transformParam);

        foreach ($remoteMap as $remoteClass => $maps) {
            $remoteIds = $result[$remoteClass] = [];

            foreach ($maps as $map) {
                if ($this->isIncludeTransformField($map) || !in_array($map, $transformParamFields, true)) {
                    continue;
                }

                $ids = Str::contains($map, '*')
                    ? Arr::collapse(Arr::pluck($data, $map))
                    : Arr::pluck($data, $map);
                $ids and $remoteIds = array_merge($remoteIds, $ids);
            }

            $remoteIds = array_filter(array_unique($remoteIds));

            if (!empty($remoteIds)) {
                if (Str::contains($remoteClass, 'Trawind\Remotes')) {
                    $remote = app($remoteClass);
                    $promises[$remoteClass] = $httpClient->getAsync($remote->baseRoute,
                        $remote->buildPromiseOptions($remoteIds));
                } else {
                    $result[$remoteClass] = app($remoteClass)->getListById($remoteIds);
                }
            }
        }


        $result = array_merge($result, HttpClientHelper::resolve($promises));
        foreach ($data as &$item) {

            foreach ($remoteMap as $remoteClass => $maps) {
                foreach ($maps as $map) {
                    if ($this->isIncludeTransformField($map) || !in_array($map, $transformParamFields, true)) {
                        continue;
                    }

                    $fieldKey = substr($map, 0, -3);
                    if (Str::contains($map, '*')) {
                        foreach (data_get($item, $map) as $i => $remoteId) {
                            $_map = Str::replaceFirst('*', $i, $map);
                            $_fieldKey = Str::replaceFirst('*', $i, $fieldKey);
                            $remoteResult = $result[$remoteClass][data_get($item, $_map)] ?? [];
                            $remoteResult = Arr::only($remoteResult, $transformParam[$map]);
                            Arr::set($item, $_fieldKey, ['data' => $remoteResult]);
                        }
                    } else {
                        $remoteResult = $result[$remoteClass][data_get($item, $map)] ?? [];
                        $remoteResult = Arr::only($remoteResult, $transformParam[$map]);
                        Arr::set($item, $fieldKey, ['data' => $remoteResult]);
                    }
                }
            }
        }

        return $data;
    }

}